# -*- encoding: utf-8 -*-
##############################################################################
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see http://www.gnu.org/licenses/.
#
##############################################################################

from odoo import models, fields, api
from odoo.tools.translate import _
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_round


class StockMove(models.Model):
    _inherit = 'stock.move'

    @api.multi
    def action_done(self):
        for move in self:
            if move.location_id.not_allow_negative_stock:
                qty=move._compute_quantities_dict()-move.quantity_done
                if qty<0:
                # if pack.qty_done>pack.product_qty:
                    raise ValidationError(_(' %s.' +u'物料移动后在该库位的库存数量为'+' %s.' +u',不允许移动！')%(move.product_id.display_name,qty))
        return super(StockMove, self).action_done()

class StockPicking(models.Model):
    _inherit = 'stock.picking'

    @api.multi
    def do_new_transfer(self):
        for pick in self:
            for pack in pick.pack_operation_product_ids:
                if pack.location_id.not_allow_negative_stock:
                    qty=pack._compute_quantities_dict()-pack.qty_done
                    if qty<0:
                        raise ValidationError(_(' %s.' +u'物料移动后在该库位的库存数量为'+' %s.' +u',不允许移动！')%(pack.product_id.display_name,qty))
        return super(StockPicking, self).do_new_transfer()

class Stocklocation(models.Model):
    _inherit = 'stock.location'
    not_allow_negative_stock = fields.Boolean(u'不允许负库存', default=False)

class stock_pack_operation(models.Model):
    _inherit = 'stock.pack.operation'

    @api.multi
    def _compute_quantities_dict(self):
        domain_quant_loc, domain_move_in_loc, domain_move_out_loc = self._get_domain_locations_new()
        domain_quant = [('product_id', '=', self.product_id.id)] + domain_quant_loc
        Quant = self.env['stock.quant']
        quants_res = dict((item['product_id'][0], item['qty']) for item in
                          Quant.read_group(domain_quant, ['product_id', 'qty'], ['product_id']))

        res = dict()
        for line in self.with_context(prefetch_fields=False):
            res[line.id] = {}
            qty_available = quants_res.get(line.product_id.id, 0.0)
            res[line.id]['location_product_available'] = float_round(qty_available,
                                                                     precision_rounding=line.product_uom_id.rounding)

        # return res
        return float_round(qty_available,precision_rounding=line.product_uom_id.rounding)

    def _get_domain_locations_new(self):
        company_id = False
        compute_child = True
        location_ids = []
        if self.location_id:
            location_ids.append(self.location_id.id)
        operator = compute_child and 'child_of' or 'in'
        domain = company_id and ['&', ('company_id', '=', company_id)] or []
        locations = self.env['stock.location'].browse(location_ids)
        # TDE FIXME: should move the support of child_of + auto_join directly in expression
        # The code has been modified because having one location with parent_left being
        # 0 make the whole domain unusable
        hierarchical_locations = locations.filtered(
            lambda location: location.parent_left != 0 and operator == "child_of")
        other_locations = locations.filtered(
            lambda location: location not in hierarchical_locations)  # TDE: set - set ?
        loc_domain = []
        dest_loc_domain = []
        for location in hierarchical_locations:
            loc_domain = loc_domain and ['|'] + loc_domain or loc_domain
            loc_domain += ['&',
                           ('location_id.parent_left', '>=', location.parent_left),
                           ('location_id.parent_left', '<', location.parent_right)]
            dest_loc_domain = dest_loc_domain and ['|'] + dest_loc_domain or dest_loc_domain
            dest_loc_domain += ['&',
                                ('location_dest_id.parent_left', '>=', location.parent_left),
                                ('location_dest_id.parent_left', '<', location.parent_right)]
        if other_locations:
            loc_domain = loc_domain and ['|'] + loc_domain or loc_domain
            loc_domain = loc_domain + [('location_id', operator, [location.id for location in other_locations])]
            dest_loc_domain = dest_loc_domain and ['|'] + dest_loc_domain or dest_loc_domain
            dest_loc_domain = dest_loc_domain + [
                ('location_dest_id', operator, [location.id for location in other_locations])]
        return (
            domain + loc_domain,
            domain + dest_loc_domain + ['!'] + loc_domain if loc_domain else domain + dest_loc_domain,
            domain + loc_domain + ['!'] + dest_loc_domain if dest_loc_domain else domain + loc_domain
        )


class stock_move(models.Model):
    _inherit = 'stock.move'

    @api.multi
    def _compute_quantities_dict(self):
        domain_quant_loc, domain_move_in_loc, domain_move_out_loc = self._get_domain_locations_new()
        domain_quant = [('product_id', '=', self.product_id.id)] + domain_quant_loc
        Quant = self.env['stock.quant']
        quants_res = dict((item['product_id'][0], item['qty']) for item in
                          Quant.read_group(domain_quant, ['product_id', 'qty'], ['product_id']))

        res = dict()
        for line in self.with_context(prefetch_fields=False):
            res[line.id] = {}
            qty_available = quants_res.get(line.product_id.id, 0.0)
            res[line.id]['location_product_available'] = float_round(qty_available,
                                                                     precision_rounding=line.product_uom.rounding)

        # return res
        return float_round(qty_available,precision_rounding=line.product_uom.rounding)

    def _get_domain_locations_new(self):
        company_id = False
        compute_child = True
        location_ids = []
        if self.location_id:
            location_ids.append(self.location_id.id)
        operator = compute_child and 'child_of' or 'in'
        domain = company_id and ['&', ('company_id', '=', company_id)] or []
        locations = self.env['stock.location'].browse(location_ids)
        # TDE FIXME: should move the support of child_of + auto_join directly in expression
        # The code has been modified because having one location with parent_left being
        # 0 make the whole domain unusable
        hierarchical_locations = locations.filtered(
            lambda location: location.parent_left != 0 and operator == "child_of")
        other_locations = locations.filtered(
            lambda location: location not in hierarchical_locations)  # TDE: set - set ?
        loc_domain = []
        dest_loc_domain = []
        for location in hierarchical_locations:
            loc_domain = loc_domain and ['|'] + loc_domain or loc_domain
            loc_domain += ['&',
                           ('location_id.parent_left', '>=', location.parent_left),
                           ('location_id.parent_left', '<', location.parent_right)]
            dest_loc_domain = dest_loc_domain and ['|'] + dest_loc_domain or dest_loc_domain
            dest_loc_domain += ['&',
                                ('location_dest_id.parent_left', '>=', location.parent_left),
                                ('location_dest_id.parent_left', '<', location.parent_right)]
        if other_locations:
            loc_domain = loc_domain and ['|'] + loc_domain or loc_domain
            loc_domain = loc_domain + [('location_id', operator, [location.id for location in other_locations])]
            dest_loc_domain = dest_loc_domain and ['|'] + dest_loc_domain or dest_loc_domain
            dest_loc_domain = dest_loc_domain + [
                ('location_dest_id', operator, [location.id for location in other_locations])]
        return (
            domain + loc_domain,
            domain + dest_loc_domain + ['!'] + loc_domain if loc_domain else domain + dest_loc_domain,
            domain + loc_domain + ['!'] + dest_loc_domain if dest_loc_domain else domain + loc_domain
        )
